/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.jili.ubert.clientapi;

import com.jili.ubert.clientapi.until.UnWorkException;
import com.jili.ubert.code.server2client.MsgResult;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author ChengJili
 */
class TradeNettyClient implements Runnable {

    private Channel sendchannel;
    private String host;
    private int port;
    private boolean isSSL;
    private boolean isZlib;
    private TradeRequest tradeClient;
    private static final Log log = LogFactory.getLog(TradeNettyClient.class);
    final BlockingQueue<MsgResult> connectAnswer = new SynchronousQueue<>();

    public TradeNettyClient() {
    }

    public TradeNettyClient(String host, int port, boolean isSSL, boolean isZlib, TradeRequest tradeClient) {
        this.host = host;
        this.port = port;
        this.isSSL = isSSL;
        this.isZlib = isZlib;
        this.tradeClient = tradeClient;
    }

    public void config(String host, int port, boolean isSSL, boolean isZlib, TradeRequest tradeClient) {
        this.host = host;
        this.port = port;
        this.isSSL = isSSL;
        this.isZlib = isZlib;
        this.tradeClient = tradeClient;
    }

    public MsgResult Connect(String host, int port, boolean isSSL, boolean isZlib, TradeRequest tradeClient) {
        this.host = host;
        this.port = port;
        this.isSSL = isSSL;
        this.isZlib = isZlib;
        this.tradeClient = tradeClient;
        MsgResult ret = new MsgResult();
        ret.success = false;
        // Configure the client.
        EventLoopGroup group = new NioEventLoopGroup();
        try {

            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    /*
                     .option(ChannelOption.TCP_NODELAY, true)
                     */
                    .handler(new TradeNettyClientInitializer(isSSL, isZlib, tradeClient));
            Channel f = b.connect(host, port).sync().channel();
            this.sendchannel = f;
            this.SendSYNCMsg(0, 0, new byte[1]);
            ret.setWord("连接成功");
            ret.success = true;
        } catch (InterruptedException e) {
            ret.success = false;
            ret.setWord(e.getMessage());
            log.info("登陆失败原因：" + ret.success + "  " + ret.getWord());
        } finally {
        //    group.shutdownGracefully();
            log.debug("登陆结果：" + ret.success + "  " + ret.getWord());
        }
        return ret;
    }

    public ChannelFuture SendMsg(int cmd, int RequstID, byte[] data) {
        if (sendchannel.isWritable()) {
            MsgEntity msg = new MsgEntity();
            return msg.SendMsg(sendchannel, cmd, RequstID, data);
        } else {
            throw new UnWorkException("不可写");
        }
    }

    public TradeClientHanlder SendSYNCMsg(int cmd, int RequstID, byte[] data) {
        Channel ch = this.sendchannel;
        log.info(ch.id() + "active:" + ch.isActive() + "  " + ch.isOpen() + " " + ch.isRegistered() + " " + ch.isWritable());
        //    if (sendchannel.isWritable()) {
        MsgEntity msg = new MsgEntity();
        ChannelFuture f = msg.SendMsg(sendchannel, cmd, RequstID, data);
        return f.channel().pipeline().get(TradeClientHanlder.class);
    }

    public Channel getChannel() {
        return sendchannel;
    }

    @Override
    public void run() {
        log.debug("开始登陆新版本：1.0.0");
        MsgResult ret = new MsgResult();
        ret.success = false;
        // Configure the client.
        EventLoopGroup group = new NioEventLoopGroup();
        try {
/*
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                //    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new TradeNettyClientInitializer(isSSL, isZlib, tradeClient));
            Channel ch = b.connect(host, port).sync().channel();
        */
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioSocketChannel.class)
             .handler(new TradeNettyClientInitializer(isSSL, isZlib, tradeClient));

            // Start the connection attempt.
            Channel ch = b.connect(host, port).sync().channel();
            this.sendchannel = ch;
            /*
            log.info(ch.id() + "active:" + ch.isActive() + "  " + ch.isOpen() + " " + ch.isRegistered() + " " + ch.isWritable());
            this.SendSYNCMsg( 0, 0, new byte[1]);
                    */
            ret.setWord("连接成功");
            ret.success = true;

        } catch (InterruptedException e) {
            ret.success = false;
            ret.setWord(e.getMessage());
            log.info("登陆失败原因：" + ret.success + "  " + ret.getWord());
        } finally {
            if (!ret.success){
                group.shutdownGracefully();
            }
            connectAnswer.offer(ret);
            log.debug("登陆结果：" + ret.success + "  " + ret.getWord());
        }
        
    }
    public void close(){
        try {
            this.sendchannel.closeFuture().sync();
        } catch (InterruptedException ex) {
            log.info(ex);
        }
    }

    MsgResult getConnectRST() {
        boolean interrupted = false;
        try {
            for (;;) {
                try {
                    return connectAnswer.take();
                } catch (InterruptedException ignore) {
                    interrupted = true;
                }
            }
        } finally {
            if (interrupted) {
                Thread.currentThread().interrupt();
            }
        }
    }
}
